package org.zstack.core.componentloader; import org.springframework.beans.MutablePropertyValues; import org.springframework.beans.PropertyValue; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.xml.BeanDefinitionDecorator; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.util.xml.DomUtils; import org.w3c.dom.Attr; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.zstack.header.exception.CloudRuntimeException; import org.zstack.utils.Utils; import org.zstack.utils.logging.CLogger; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class PluginDefinitionParser implements BeanDefinitionDecorator { private static final String EXTENSION_NODE = "zstack:extension"; private static final String PLUGIN_NODE = "zstack:plugin"; private static final CLogger logger = Utils.getLogger(PluginDefinitionParser.class); private List<PluginExtension> parsePlugin(List<Element> all, BeanDefinition bean, String beanName) { List<PluginExtension> exts = new ArrayList<PluginExtension>(all.size() - 1); boolean find = false; for (Element e : all) { if (e.getTagName().equals(PLUGIN_NODE)) { find = true; } if (e.getTagName().equals(EXTENSION_NODE)) { assert find == true; PluginExtension ext = new PluginExtension(); ext.setBeanClassName(bean.getBeanClassName()); ext.setBeanName(beanName); String iface = e.getAttribute("interface"); if (iface != null) { ext.setReferenceInterface(iface.trim()); } String iref = e.getAttribute("instance-ref"); if (iref != null) { ext.setInstanceId(iref.trim()); } String order = e.getAttribute("order"); if (order != null) { order = order.trim(); if (!order.equals("")) { ext.setOrder(Integer.valueOf(order)); } } NamedNodeMap attrMap = e.getAttributes(); for (int i=0; i<attrMap.getLength(); i++) { Attr attr = (Attr) attrMap.item(i); ext.putAttribute(attr.getNodeName(), attr.getNodeValue()); } exts.add(ext); } } return exts; } @Override public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder holder, ParserContext ctx) { if (!ctx.getRegistry().containsBeanDefinition(PluginRegistry.PLUGIN_REGISTRY_BEAN_NAME)) { BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(PluginRegistryImpl.class); ctx.getRegistry().registerBeanDefinition(PluginRegistry.PLUGIN_REGISTRY_BEAN_NAME, builder.getBeanDefinition()); logger.debug("No BeanDefinition for PluginRegistry found, create and register one"); } Element root = (Element) node; List<Element> all = new ArrayList<Element>(6); all.add(root); List<Element> children = DomUtils.getChildElementsByTagName(root, new String[] { EXTENSION_NODE }); all.addAll(children); List<PluginExtension> exts = parsePlugin(all, holder.getBeanDefinition(), holder.getBeanName()); if (!exts.isEmpty()) { PluginExtension ext = exts.get(0); BeanDefinition registryBean = ctx.getRegistry().getBeanDefinition(PluginRegistry.PLUGIN_REGISTRY_BEAN_NAME); MutablePropertyValues props = registryBean.getPropertyValues(); PropertyValue prop = props.getPropertyValue(PluginRegistry.PLUGIN_REGISTRYIMPL_PLUGINS_FIELD_NAME); if (prop == null) { Map<String, List<PluginExtension>> extensions = new HashMap<String, List<PluginExtension>>(1); extensions.put(ext.getBeanClassName(), exts); prop = new PropertyValue(PluginRegistry.PLUGIN_REGISTRYIMPL_PLUGINS_FIELD_NAME, extensions); logger.debug("No 'extensions' property found in PluginRegistry bean definition, create a new one"); props.addPropertyValue(prop); } else { Map<String, List<PluginExtension>> extensions = (Map<String, List<PluginExtension>>) prop.getValue(); List<PluginExtension> oexts = extensions.get(ext.getBeanClassName()); if (oexts == null) { oexts = new ArrayList<PluginExtension>(exts.size()); extensions.put(ext.getBeanClassName(), oexts); } for (PluginExtension e : exts) { if (oexts.contains(e)) { throw new CloudRuntimeException(String.format("duplicated extension declaration[interfaceRef:%s, beanName:%s, beanClass:%s]", e.getReferenceInterface(), ext.getBeanName(), ext.getBeanClassName())); } } oexts.addAll(exts); } logger.debug(String.format("Add extensions declared by bean[name=%s, class=%s] to 'extensions' property of PluginRegistry bean definition", ext.getBeanName(), ext.getBeanClassName())); } return holder; } }